import os
import re
import uuid

from django.contrib.auth import authenticate
from django.db.models import QuerySet
from django.http import HttpResponse
from django.shortcuts import render
from user.models import Upload, Praise, Comment
# Create your views here.
from rest_framework.permissions import BasePermission, AllowAny, IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework_jwt.settings import api_settings
from rest_framework import mixins, status
from stegano import lsb

from steganography.settings import BASE_DIR
from user.models import User
from user.serializers import UserSerializer, PraiseSerializer, CommentSerializer, UploadSerializer, \
    CommonUploadSerializer
from utils.response import ReturnMsg
from utils.upload import uploadFile, upload


class IsVip(BasePermission):
    def has_permission(self, request, view):
        return bool(request.user.is_authenticated and request.user.vip)


class LoginAPIView(APIView):
    permission_classes = [AllowAny]

    def post(self, request):
        request: Request
        data = request.data
        username = data.get('username')
        password = data.get('password')

        if not all([username, password]):
            return Response(ReturnMsg(code=0, msg="错误", errors="用户名或密码未提供").dict())

        user = authenticate(username=username,
                            password=password)

        user: User
        # 判断是否为空,如果为空,返回
        if user is None:
            return Response(ReturnMsg(code=0, msg="错误", errors="用户名或密码错误").dict())

        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        return Response(ReturnMsg(data={
            "token": token,
            "username": user.username,
            "name": user.name,
            "text": user.text,
            "vip": user.vip,
            "avatar": user.avatar,
            "b1": user.b1,
            "b2": user.b2,
            "b3": user.b3,
        }).dict())


class RegisterView(APIView):
    permission_classes = [AllowAny]

    def post(self, request):
        request: Request
        data = request.data
        username = data.get('username')
        password = data.get('password')
        password2 = data.get('password2')
        email = data.get('email')
        name = data.get('name')

        if not all([username, password, password2, email, name]):
            return Response(ReturnMsg(code=0, msg="错误", errors="参数未完全提供").dict())
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return Response(ReturnMsg(code=0, msg="错误", errors="用户名必须为5-20个字符").dict())

        if not re.match(r'^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$', email):
            return Response(ReturnMsg(code=0, msg="错误", errors="邮箱格式不合法").dict())
        # 判断密码是否是5-17个数字
        if not re.match(r'^[a-zA-Z]\w{5,17}$', password):
            return Response(ReturnMsg(code=0, msg="错误", errors="密码必须以字母开头，长度在6~18之间，只能包含字母、数字和下划线").dict())
        # 判断两次密码是否一致
        if password != password2:
            return Response(ReturnMsg(code=0, msg="错误", errors="两次密码输入不一致").dict())
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            user = None

        if user is not None:
            return Response(ReturnMsg(code=0, msg="错误", errors="用户名已被注册").dict())
        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            email=email,
                                            name=name)
        except:
            return Response(ReturnMsg(code=0, msg="错误", errors="注册账号失败").dict())

        return Response(ReturnMsg(data={
            "username": user.username
        }).dict())


class FileUploadView(APIView):

    def post(self, request):
        file_obj = request.data.get('file')
        url = upload(file=file_obj)
        return Response(ReturnMsg(data={
            "url": url
        }).dict(), status=200)


class AvatarUploadView(APIView):

    def post(self, request):
        file_obj = request.data.get('file')
        url = upload(file=file_obj)
        request.user.avatar = url
        request.user.save()
        return Response(ReturnMsg(data={
            "avatar": url
        }).dict(), status=200)


class ImageUploadView(APIView):

    def post(self, request):
        file = request.data.get('file')
        text = request.data.get('text')

        files = "files"
        try:
            number = uuid.uuid4()
            # 生成文件名
            filename = file.name.split(".")
            if len(filename) > 1:
                base_fil_name = str(number) + "." + filename[-1]
            else:
                base_fil_name = str(number)
            destination = open(os.path.join(BASE_DIR, files, base_fil_name), 'wb+')
            for chunk in file.chunks():  # 分块写入文件
                destination.write(chunk)
            destination.close()
            name = str(uuid.uuid4())
            lsb.hide(os.path.join(BASE_DIR, files, base_fil_name), text).save(
                os.path.join(BASE_DIR, files, f"{name}.png"))
            url = uploadFile(f"{name}.png", open(os.path.join(BASE_DIR, files, f"{name}.png"), "rb"))
            Upload.objects.create(uploader_id=self.request.user.id, url=url, text=text)
        except:
            try:
                os.remove(os.path.join(BASE_DIR, files, base_fil_name))
            except:
                pass
            try:
                os.remove(os.path.join(BASE_DIR, files, f"{name}.png"))
            except:
                pass
            return Response(ReturnMsg(code=0, msg="错误", errors="加密图片失败").dict())
        os.remove(os.path.join(BASE_DIR, files, base_fil_name))
        os.remove(os.path.join(BASE_DIR, files, f"{name}.png"))
        return Response(ReturnMsg(data={
            "src": f"{name}.png"
        }).dict(), status=200)


class UserViewSet(GenericViewSet, mixins.ListModelMixin, mixins.UpdateModelMixin):
    serializer_class = UserSerializer

    def get_queryset(self):
        return User.objects.filter(id=self.request.user.id)

    def list(self, request, *args, **kwargs):
        response = super().list(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)

    def update(self, request, *args, **kwargs):
        response = super().update(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)


class CommentViewSet(GenericViewSet, mixins.ListModelMixin, mixins.DestroyModelMixin, mixins.CreateModelMixin):
    serializer_class = CommentSerializer

    def get_queryset(self):
        return Comment.objects.all()

    def list(self, request, *args, **kwargs):
        response = super().list(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)

    def create(self, request, *args, **kwargs):
        image = int(request.data.get('image'))
        text = request.data.get('text')
        user = request.user.id
        try:
            comment = Comment.objects.create(image_id=image, text=text, user_id=user)
        except:
            return Response(ReturnMsg(code=0, msg="错误", errors="提交失败").dict())
        return Response(ReturnMsg(data=CommentSerializer(comment).data).dict(), status=200)


    def destroy(self, request, *args, **kwargs):
        response = super().destroy(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)


class SelfUploadViewSet(GenericViewSet, mixins.ListModelMixin, mixins.DestroyModelMixin):
    serializer_class = UploadSerializer

    def get_queryset(self):
        return Upload.objects.filter(uploader_id=self.request.user.id)

    def list(self, request, *args, **kwargs):
        response = super().list(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)

    def destroy(self, request, *args, **kwargs):
        response = super().destroy(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)


class UploadViewSet(GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin):
    def get_serializer_class(self):
        if self.request.user.vip:
            return UploadSerializer
        else:
            return CommonUploadSerializer

    def get_queryset(self):
        return Upload.objects.all()

    def list(self, request, *args, **kwargs):
        response = super().list(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)

    def retrieve(self, request, *args, **kwargs):
        response = super().retrieve(request, args, kwargs)
        return Response(ReturnMsg(data=response.data).dict(), status=200)


class PraiseView(APIView):
    def get(self, request):
        temp = []
        user_id = request.user.id

        praises = Praise.objects.filter(user_id=user_id)
        for praise in praises:
            temp.append(praise.image_id)
        return Response(ReturnMsg(data=temp).dict(), status=200)

    def post(self, request):
        image_id = request.data.get('image')
        try:
            praise = Praise.objects.create(image_id=image_id, user_id=request.user.id)
            praise.image.uploader.b1 += 1
            praise.image.uploader.save()
        except:
            return Response(ReturnMsg(code=0, msg="错误").dict())
        return Response(ReturnMsg().dict(), status=200)

    def delete(self, request):
        image_id = request.data.get('image')
        try:
            praises = Praise.objects.filter(image_id=image_id, user_id=request.user.id)
            for praise in praises:
                praise.image.uploader.b1 -= 1
                praise.image.uploader.save()
                praise.delete()
        except:
            return Response(ReturnMsg(code=0, msg="错误").dict())
        return Response(ReturnMsg().dict(), status=200)

